from langchain.agents import create_agent
from langchain_deepseek import ChatDeepSeek
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import interrupt
from langchain_core.tools import tool


# 定义一个需要人工审核的敏感工具函数，用于模拟宾馆预订流程。
# 参数:
#   hotel_name (str): 要预订的宾馆名称
# 返回值:
#   str: 表示操作结果的字符串信息
@tool(return_direct=True)
def book_hotel(hotel_name: str):
    """预定宾馆"""
    response = interrupt(
        f"正准备执⾏'book_hotel'⼯具预定宾馆，相关参数名： {{'hotel_name': {hotel_name}}}. "
        "请选择OK，表示同意，或者选择edit，提出补充意⻅."
    )
    if response["type"] == "OK":
        pass
    elif response["type"] == "edit":
        hotel_name = response["args"]["hotel_name"]
    else:
        raise ValueError(f"Unknown response type: {response['type']}")
    return f"成功在 {hotel_name} 预定了⼀个房间."


# 使用内存存储检查点状态，适用于单次会话或测试场景
checkpointer = InMemorySaver()

# 初始化DeepSeek模型客户端，并配置相关参数以控制生成行为
llm = ChatDeepSeek(
    model="deepseek-chat",  # 指定使用的模型名称
    api_key="sk-ddad02a64c4c47ea9f6f526ef47cb602",  # 替换为你的API Key
    temperature=0.7,  # 控制生成结果的随机性，0表示更确定性的输出
    max_tokens=None,  # 生成内容的最大长度，None代表使用模型默认值
    timeout=60,  # 请求超时设置（单位秒）
    max_retries=2,  # 请求失败时最大重试次数
)

# 创建代理实例，绑定语言模型、可用工具以及状态管理器
agent = create_agent(
    model=llm,
    tools=[book_hotel],
    checkpointer=checkpointer,
)

# 设置配置项，包括线程ID等可配置参数
config = {
    "configurable": {
        "thread_id": "1"
    }
}

# 启动代理并处理用户请求，逐块打印响应内容
for chunk in agent.stream(
        {"messages": [{"role": "user", "content": "帮我在图灵宾馆预定⼀个房间"}]},
        config
):
    print(chunk)
    print("\n")



from langgraph.types import Command

# 遍历agent的流式输出结果
# 通过发送Command指令来恢复或编辑对话状态
# 每次迭代处理一个数据块，并打印相关信息
for chunk in agent.stream(
        Command(resume={"type": "OK"}),
        # Command(resume={"type": "edit", "args": {"hotel_name": "三号宾馆"}}),
        config
):
    # 打印当前数据块内容
    print(chunk)
    # 打印工具消息中的最后一条消息内容
    print(chunk['tools']['messages'][-1].content)
    # 打印空行用于分隔输出
    print("\n")
